package com.xzy.mybatis.cipher.support.strategy.parse;

import cn.hutool.core.util.StrUtil;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.statement.SQLSelectStatement;
import com.xzy.mybatis.cipher.support.registry.CryptoMetadataRegistry;
import com.xzy.mybatis.cipher.support.registry.DataCryptoStrategyRegistry;
import com.xzy.mybatis.cipher.support.strategy.crypto.CryptoStrategy;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author xzy.xiao
 * @since 2025/1/14  16:31
 */
@Slf4j
public class SelectParseStrategy extends ParseStrategy {

    public SelectParseStrategy(CryptoMetadataRegistry cryptoMetadataRegistry, DataCryptoStrategyRegistry dataCryptoStrategyRegistry) {
        super(cryptoMetadataRegistry, dataCryptoStrategyRegistry);
    }

    /**
     * SELECT ... FROM ... WHERE ...
     */
    @Override
    public List<Object> parse(String datasourceName, SQLStatement sqlStatement, List<Object> originalPropertyValueList) {
        SQLSelectStatement sqlSelectStatement = (SQLSelectStatement) sqlStatement;

        Map<String, String> aliasTableMap = new HashMap<>();
        List<String> whereColumnList = extractedQuery(sqlSelectStatement.getSelect().getQuery(), aliasTableMap);
        if (whereColumnList.isEmpty()) {
            return originalPropertyValueList;
        }

        // WHERE
        List<Object> encryptedPropertyValueList = new ArrayList<>(originalPropertyValueList.size());
        for (int i = 0; i < whereColumnList.size(); i++) {

            Object originalPropertyValue = originalPropertyValueList.get(i);
            String whereColumn = whereColumnList.get(i);

            // 表别名
            String tableName;
            String columnName;
            if (whereColumn.contains(".")) {
                String[] split = whereColumn.split("\\.");
                tableName = aliasTableMap.get(split[0]);
                columnName = split[1];
            } else {
                tableName = aliasTableMap.get(null);
                columnName = whereColumnList.get(i);
                if (StrUtil.isBlank(tableName)) {
                    throw new RuntimeException("column " + columnName + " match table failure!");
                }
            }

            if (!cryptoMetadataRegistry.isCryptoColumn(datasourceName, tableName, columnName)) {
                encryptedPropertyValueList.add(originalPropertyValue);
                continue;
            }

            CryptoStrategy cryptoStrategy = dataCryptoStrategyRegistry.getStrategy(datasourceName, tableName, columnName);
            if (null == cryptoStrategy) {
                encryptedPropertyValueList.add(originalPropertyValue);
                continue;
            }

            String encryptedPropertyValue = cryptoStrategy.encrypt((String) originalPropertyValue);
            encryptedPropertyValueList.add(encryptedPropertyValue);
        }

        log.debug("Parsed select sql.\n\t==> original property value:{}\n\t==> encrypted property value:{}", originalPropertyValueList, encryptedPropertyValueList);
        return encryptedPropertyValueList;
    }

}
